﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Web;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
using Proxy;
using SIM.Geo.UI;
using SIM.Util;

namespace OpenXMLExcel.SLExcelUtility
{
    public class SLExcelReader
    {
        private string GetColumnName(string cellReference)
        {
            var regex = new Regex("[A-Za-z]+");
            var match = regex.Match(cellReference);

            return match.Value;
        }

        private int ConvertColumnNameToNumber(string columnName)
        {
            var alpha = new Regex("^[A-Z]+$");
            if (!alpha.IsMatch(columnName)) throw new ArgumentException();

            char[] colLetters = columnName.ToCharArray();
            Array.Reverse(colLetters);

            var convertedValue = 0;
            for (int i = 0; i < colLetters.Length; i++)
            {
                char letter = colLetters[i];
                int current = i == 0 ? letter - 65 : letter - 64; // ASCII 'A' = 65
                convertedValue += current * (int)Math.Pow(26, i);
            }

            return convertedValue;
        }

        private IEnumerator<Cell> GetExcelCellEnumerator(Row row)
        {
            int currentCount = 0;
            foreach (Cell cell in row.Descendants<Cell>())
            {
                string columnName = GetColumnName(cell.CellReference);

                int currentColumnIndex = ConvertColumnNameToNumber(columnName);

                for (; currentCount < currentColumnIndex; currentCount++)
                {
                    var emptycell = new Cell() { DataType = null, CellValue = new CellValue(string.Empty) };
                    yield return emptycell;
                }

                yield return cell;
                currentCount++;
            }
        }

        private string ReadExcelCell(Cell cell, WorkbookPart workbookPart)
        {
            var cellValue = cell.CellValue;
            var text = (cellValue == null) ? cell.InnerText : cellValue.Text;
            if ((cell.DataType != null) && (cell.DataType == CellValues.SharedString))
            {
                text = workbookPart.SharedStringTablePart.SharedStringTable.Elements<SharedStringItem>().ElementAt(
                        Convert.ToInt32(cell.CellValue.Text)).InnerText;
            }

            return (text ?? string.Empty).Trim();
        }

        public SLExcelData ReadExcel(HttpPostedFileBase file)
        {
            var data = new SLExcelData();

            // Check if the file is excel
            if (file.ContentLength <= 0)
            {
                data.Status.Message = "You uploaded an empty file";
                return data;
            }

            if (file.ContentType != "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
            {
                data.Status.Message = "Please upload a valid excel file of version 2007 and above";
                return data;
            }

            // Open the excel document
            WorkbookPart workbookPart; List<Row> rows;
            try
            {
                var document = SpreadsheetDocument.Open(file.InputStream, false);
                workbookPart = document.WorkbookPart;

                var sheets = workbookPart.Workbook.Descendants<Sheet>();
                var sheet = sheets.First();
                data.SheetName = sheet.Name;

                var workSheet = ((WorksheetPart)workbookPart.GetPartById(sheet.Id)).Worksheet;
                var columns = workSheet.Descendants<Columns>().FirstOrDefault();
                data.ColumnConfigurations = columns;

                var sheetData = workSheet.Elements<SheetData>().First();
                rows = sheetData.Elements<Row>().ToList();
            }
            catch (Exception e)
            {
                data.Status.Message = "Unable to open the file";
                return data;
            }

            // Read the header
            if (rows.Count > 0)
            {
                var row = rows[0];
                var cellEnumerator = GetExcelCellEnumerator(row);
                while (cellEnumerator.MoveNext())
                {
                    var cell = cellEnumerator.Current;
                    var text = ReadExcelCell(cell, workbookPart).Trim();
                    data.Headers.Add(text);
                }
            }

            // Read the sheet data
            if (rows.Count > 1)
            {
                for (var i = 1; i < rows.Count; i++)
                {
                    var dataRow = new List<string>();
                    data.DataRows.Add(dataRow);
                    var row = rows[i];
                    var cellEnumerator = GetExcelCellEnumerator(row);
                    while (cellEnumerator.MoveNext())
                    {
                        var cell = cellEnumerator.Current;
                        var text = ReadExcelCell(cell, workbookPart).Trim();
                        dataRow.Add(text);
                    }
                }
            }

            return data;
        }

        #region Importacion de datos
        /// <summary>
        /// Carga taladros
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public List<SondajeImportacion> ImportarTaladro(string fileName)
        {
            SondajeImportacion taladro = null;
            List<SondajeImportacion> taladros = new List<SondajeImportacion>();
            try
            {

                WorkbookPart workbookPart; List<Row> rows;

                var document = SpreadsheetDocument.Open(fileName, true);
                workbookPart = document.WorkbookPart;

                var sheets = workbookPart.Workbook.Descendants<Sheet>();
                var sheet = sheets.First();

                var workSheet = ((WorksheetPart)workbookPart
                    .GetPartById(sheet.Id)).Worksheet;
                var columns = workSheet.Descendants<Columns>().FirstOrDefault();

                var sheetData = workSheet.Elements<SheetData>().First();
                rows = sheetData.Elements<Row>().ToList();

                var data = new SLExcelData();

                // Lee la cabeceras
                if (rows.Count > 0)
                {
                    var row = rows[0];
                    var cellEnumerator = GetExcelCellEnumerator(row);
                    while (cellEnumerator.MoveNext())
                    {
                        var cell = cellEnumerator.Current;
                        var text = ReadExcelCell(cell, workbookPart).Trim();
                        data.Headers.Add(text);
                    }
                }

                // Lee la Data
                if (rows.Count > 1)
                {
                    for (var i = 1; i < rows.Count; i++)
                    {
                        var dataRow = new List<string>();
                        data.DataRows.Add(dataRow);
                        var row = rows[i];
                        var cellEnumerator = GetExcelCellEnumerator(row);
                        while (cellEnumerator.MoveNext())
                        {
                            var cell = cellEnumerator.Current;
                            var text = ReadExcelCell(cell, workbookPart).Trim();
                            dataRow.Add(text);
                        }
                    }
                }

                int seccion;
                string aux = string.Empty;
                int fila;
                double este;
                double norte;
                double cota;
                double azimut;
                double inclinacion;
                double distancia;
                DateTime fecha;
                string codigo = string.Empty;
                double desde;
                double hasta;

                //Poblar taladros importados
                foreach (var item in data.DataRows)
                {
                    //Verifica la cantidad de columnas, debe ser 14
                    if (item.Count >= 14)
                    {
                        
                        taladro = new SondajeImportacion();
                        taladro.TLG = item[0];

                        int.TryParse(item[1], out seccion);
                        taladro.Seccion = seccion;

                        taladro.Aux = item[2];
                        int.TryParse(item[3], out fila);
                        taladro.Fila = fila;

                        double.TryParse(item[4], out este);
                        taladro.Este = este;

                        double.TryParse(item[5], out norte);
                        taladro.Norte = norte;

                        double.TryParse(item[6], out cota);
                        taladro.Cota = cota;

                        double.TryParse(item[7], out azimut);
                        taladro.Azimut = azimut;

                        double.TryParse(item[8], out inclinacion);
                        taladro.Inclinacion = inclinacion;

                        double.TryParse(item[9], out distancia);
                        taladro.Distancia = distancia;

                        try
                        {
                            fecha = DateTime.Parse(item[10]);
                            taladro.Fecha = fecha;
                        }
                        catch (Exception)
                        {
                        }

                        taladro.CodigoMuestra = item[11];

                        double.TryParse(item[12], out desde);
                        taladro.Desde = desde;

                        double.TryParse(item[13], out hasta);
                        taladro.Hasta = hasta;

                        taladros.Add(taladro);
                    }
                }

                document.Close();
                document.Dispose();
                document = null;

            }
            catch (Exception ex)
            {

                Logger.Error("SLExcelReader.aspx:ImportarTaladro", ex);
            }

            return taladros;
        }

        /// <summary>
        /// Realiza importación de Leyes, utiliza OpenXML
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public List<MuestraSondajeImportacion> CargarLeyes(string fileName)
        {
            try
            {
                WorkbookPart workbookPart; List<Row> rows;

                var document = SpreadsheetDocument.Open(fileName, true);
                workbookPart = document.WorkbookPart;

                var sheets = workbookPart.Workbook.Descendants<Sheet>();
                var sheet = sheets.First();

                var workSheet = ((WorksheetPart)workbookPart
                    .GetPartById(sheet.Id)).Worksheet;
                var columns = workSheet.Descendants<Columns>().FirstOrDefault();

                var sheetData = workSheet.Elements<SheetData>().First();
                rows = sheetData.Elements<Row>().ToList();

                DTOMuestraSondajeImport muestrax = null;
                List<DTOMuestraSondajeImport> muestras = new List<DTOMuestraSondajeImport>();

                var data = new SLExcelData();

                // Lee la Data
                if (rows.Count > 1)
                {
                    for (var i = 1; i < rows.Count; i++)
                    {
                        var dataRow = new List<string>();
                        data.DataRows.Add(dataRow);
                        var row = rows[i];
                        var cellEnumerator = GetExcelCellEnumerator(row);
                        while (cellEnumerator.MoveNext())
                        {
                            var cell = cellEnumerator.Current;
                            var text = ReadExcelCell(cell, workbookPart).Trim();
                            dataRow.Add(text);
                        }
                    }
                }

                foreach (var item in data.DataRows)
                {
                    //Verifica la cantidad de columnas, debe ser 6
                    if (item.Count >= 6)
                    {
                        muestrax = new DTOMuestraSondajeImport();

                        muestrax.CodigoMuestraSondaje = item[0];
                        muestrax.ValorAg = item[1];
                        muestrax.ValorCu = item[2];
                        muestrax.ValorPb = item[3];
                        muestrax.ValorZn = item[4];
                        muestrax.ValorFe = item[5];
                        muestras.Add(muestrax);
                    }
                }

                //Filtra items válidos
                int longitudCodigoMuestra = int.Parse(System.Configuration.ConfigurationManager.AppSettings["longitudCodigoMuestraImportar"]);
                var muestraValidos = muestras.Where(x => x.CodigoMuestraSondaje.Length == longitudCodigoMuestra && 
                    Funciones.IsNumeric(x.CodigoMuestraSondaje.Substring(0, 7)) &&
                    (x.CodigoMuestraSondaje.Contains(Constantes.TipoSerieCodigoMuestra.SONDAJE) || x.CodigoMuestraSondaje.Contains(Constantes.TipoSerieCodigoMuestra.TALADRO)
                        || x.CodigoMuestraSondaje.Contains(Constantes.TipoSerieCodigoMuestra.CANAL) || x.CodigoMuestraSondaje.Contains(Constantes.TipoSerieCodigoMuestra.ESPECIAL))
                    ).ToList();

                //Reemplazo los datos no Validos y genera Nueva lista
                MuestraSondajeImportacion muestra = new MuestraSondajeImportacion();
                List<MuestraSondajeImportacion> muestraImportadas = new List<MuestraSondajeImportacion>();

                foreach (var item in muestraValidos)
                {
                    muestra = new MuestraSondajeImportacion();
                    item.ValorAg = (item.ValorAg != null) ? item.ValorAg.Replace('<', ' ') : item.ValorAg = string.Empty;
                    item.ValorPb = (item.ValorPb != null) ? item.ValorPb.Replace('<', ' ') : item.ValorPb = string.Empty;
                    item.ValorZn = (item.ValorZn != null) ? item.ValorZn.Replace('<', ' ') : item.ValorZn = string.Empty;
                    item.ValorCu = (item.ValorCu != null) ? item.ValorCu.Replace('<', ' ') : item.ValorCu = string.Empty;
                    item.ValorFe = "-1";

                    if (item.ValorAg == "") item.ValorAg = "-1";
                    if (item.ValorPb == "") item.ValorPb = "-1";
                    if (item.ValorZn == "") item.ValorZn = "-1";
                    if (item.ValorCu == "") item.ValorCu = "-1";

                    muestra.CodigoMuestraSondaje = item.CodigoMuestraSondaje;
                    if (Funciones.IsNumeric(item.ValorAg)) muestra.ValorAg = float.Parse(item.ValorAg);
                    if (Funciones.IsNumeric(item.ValorPb)) muestra.ValorPb = float.Parse(item.ValorPb);
                    if (Funciones.IsNumeric(item.ValorZn)) muestra.ValorZn = float.Parse(item.ValorZn);
                    if (Funciones.IsNumeric(item.ValorCu)) muestra.ValorCu = float.Parse(item.ValorCu);
                    if (Funciones.IsNumeric(item.ValorFe)) muestra.ValorFe = float.Parse(item.ValorFe);

                    muestraImportadas.Add(muestra);
                }

                document.Close();
                document.Dispose();
                document = null;

                return muestraImportadas;

            }
            catch (Exception ex)
            {
                Logger.Error("SimExcelReader:CargarLeyes", ex);
                return null;
            }
        }


        #endregion Importacion de datos
    }
}